package com.tn.rtdata
{
	import com.tn.openrpc.IRemoteMethod;
	import com.tn.openrpc.RemoteMethodError;
	import mx.rpc.IResponder;

	public class Session implements IResponder
	{

		/*============================================================================*/
		/* Public Properties                                                          */
		/*============================================================================*/

		private var _heartbeat:HeartbeatMonitor;

		public function get heartbeat():HeartbeatMonitor
		{
			return _heartbeat ||= new HeartbeatMonitor(heartbeatInterval, heartbeatMethod, listeners);
		}

		/*============================================================================*/
		/* Internal Properties                                                        */
		/*============================================================================*/

		internal var heartbeatInterval:Number;

		internal function get isClosed():Boolean
		{
			return closed;
		}

		/*============================================================================*/
		/* Private Properties                                                         */
		/*============================================================================*/

		private var closeMethod:IRemoteMethod;

		private var closed:Boolean;

		private var heartbeatMethod:IRemoteMethod;

		private var listeners:Vector.<Listener>;

		private var sessionId:String;

		/*============================================================================*/
		/* Constructor                                                                */
		/*============================================================================*/

		public function Session(
			connectMethod:IRemoteMethod,
			closeMethod:IRemoteMethod,
			heartbeatMethod:IRemoteMethod,
			heartbeatInterval:Number,
			listeners:Array)
		{
			try
			{
				this.closeMethod = closeMethod;
				this.heartbeatMethod = heartbeatMethod;
				this.heartbeatInterval = heartbeatInterval;
				this.closed = false;
				addListeners(listeners);
				connectMethod.invoke().addResponder(this);
			}
			catch (error:RemoteMethodError)
			{
				throw new SessionError(error);
			}
		}


		/*============================================================================*/
		/* Public Functions                                                           */
		/*============================================================================*/

		/**
		 * Adds a <code>listener</code>.
		 */
		public function addListener(listener:Listener):void
		{
			listeners ||= new Vector.<Listener>;
			listeners.push(listener);
		}

		/**
		 * Closes this session.
		 */
		public function close():void
		{
			try
			{
				if (!isClosed)
				{
					closeMethod.invoke(sessionId);
					heartbeat.stop();
					closed = true;
				}
			}
			catch (error:RemoteMethodError)
			{
				throw new SessionError(error);
			}
		}

		/**
		 * IResponder Listener for Connect Token
		 * @param data
		 *
		 */
		public function fault(info:Object):void
		{
			throw new SessionError(info);
		}

		/**
		 * Adds a <code>listener</code>.
		 */
		public function removeListener(listener:Listener):void
		{
			listeners.splice(listeners.indexOf(listener), 1);
		}

		/**
		 * IResponder Listener for Connect Token
		 * @param data
		 *
		 */
		public function result(data:Object):void
		{
			heartbeat.start();
		}

		/*============================================================================*/
		/* Private Functions                                                          */
		/*============================================================================*/

		private function addListeners(items:Array):void
		{
			for each (var sessionListener:Listener in listeners)
			{
				addListener(sessionListener);
			}
		}
	}
}

import com.tn.openrpc.IRemoteMethod;
import com.tn.rtdata.Listener;
import flash.utils.Timer;
import mx.rpc.IResponder;

internal class HeartbeatMonitor implements IResponder
{

	/*============================================================================*/
	/* Public Properties                                                          */
	/*============================================================================*/

	private var _timer:Timer;

	public function get timer():Timer
	{
		return _timer ||= new Timer(interval);
	}

	/*============================================================================*/
	/* Private Properties                                                         */
	/*============================================================================*/

	private var interval:Number;

	private var listeners:Vector.<Listener>;

	private var method:IRemoteMethod;

	/*============================================================================*/
	/* Constructor                                                                */
	/*============================================================================*/

	public function HeartbeatMonitor(
		interval:Number,
		method:IRemoteMethod,
		listeners:Vector.<Listener>
		)
	{
		this.interval = interval;
		this.method = method;
	}


	/*============================================================================*/
	/* Public Functions                                                           */
	/*============================================================================*/

	/**
	 * IResponder Listener Event
	 * Fires the <code>Listener.heartbeatFailed()</code> method.
	 * @param data
	 *
	 */
	public function fault(info:Object):void
	{
		for each (var sessionListener:Listener in listeners)
		{
			sessionListener.heartbeatFailed();
		}
	}

	/**
	 * IResponder Listener Event
	 * Fires the <code>Listener.heartbeatSucceeded()</code> method.
	 * @param data
	 *
	 */
	public function result(data:Object):void
	{
		for each (var sessionListener:Listener in listeners)
		{
			sessionListener.heartbeatSucceeded();
		}
	}

	public function start():void
	{
		(!timer.running) && timer.start();
	}

	public function stop():void
	{
		timer.running && timer.stop();
	}

	/*============================================================================*/
	/* Protected Functions                                                        */
	/*============================================================================*/

	protected function onIntervalReached():void
	{
		method && method.invoke();
	}
}

